#include "Socket.hpp"
#include "log.hpp"

static const uint16_t DEFAULT_PORT = 8080; // 默认端口号
int default_fd = -1;
class Select
{
public:
    // 初始化服务器
    Select(uint16_t port = DEFAULT_PORT) : _port(port)
    {
        _listen_fd = _listen_sock.Socket();
        _listen_sock.Bind(_listen_fd, _port);
        _listen_sock.Listen(_listen_fd);
        LogMessage(DEBUG, "SELECT INIT SUCCESS LISTEN_FD = %d", _listen_fd);
        // 初始化文件描述符
        for (int i = 0; i < __FD_SETSIZE; ++i)
        {
            _fd_array[i] = default_fd;
        }
    }
    // 服务器启动
    void Start()
    {
        //将监听的套接字添加到文件描述符集合中
        _fd_array[0] = _listen_fd;
        for (;;)
        {
            //定义文件描述符集合并初始化为空
            fd_set rfds;
            FD_ZERO(&rfds);
            //保存一下最大的文件描述符
            int maxfd = _fd_array[0];
            for (int i = 0; i < __FD_SETSIZE; ++i)
            {
                if (_fd_array[i] == default_fd)
                    continue;

                FD_SET(_fd_array[i], &rfds);
                if (maxfd < _fd_array[i])
                {
                    maxfd = _fd_array[i];
                    LogMessage(DEBUG, "MAX FD IS UPDATA ,MAX FD IS %d", maxfd);
                }
            }
            //设置超时时间
            struct timeval timeout = {0, 0};
            int ret = select(maxfd + 1, &rfds, nullptr, nullptr, &timeout);
            switch (ret)
            {
            case 0:
                LogMessage(DEBUG, "TIME OUT TIME:%d,%d", timeout.tv_sec, timeout.tv_usec);
                sleep(1);
                break;
            case -1:
                LogMessage(DEBUG, "SELECT FAIL");
                break;
            default:
                // 有新连接 进行处理
                LogMessage(DEBUG, "GET A NEW LINK");
                Dispatcher(rfds);
                break;
            }
        }
    }
    ~Select()
    {
    }

private:
    void PrinfFd()
    {
        std::cout << "online fd list";
        for (int i = 0; i < __FD_SETSIZE; ++i)
        {
            if (_fd_array[i] == default_fd)
                continue;

            std::cout << _fd_array[i] << " ";
        }
    }
    // select 监听到就绪
    void Accepter()
    {

        std::string client_ip;
        uint16_t client_port;
        int sock = _listen_sock.Accept(_listen_fd, &client_ip, &client_port);
        if (sock < 0)
        {
            return;
        }
        LogMessage(NORMAL, "link success %s:%u", client_ip.c_str(), client_port);
        //从_fd_array找到空位置存放新的套接字信息
        int pos = 1;
        for (; pos < __FD_SETSIZE; ++pos)
        {
            if (_fd_array[pos] != default_fd)
            {
                continue;
            }
            else
            {
                break;
            }
        }
        //满了 无法存放新连接的套接字
        if (pos == __FD_SETSIZE)
        {
            LogMessage(WARING, "SERVER IS FULL ,CLOSE SOCKET %d NOW", sock);
        }
        else
        {
            //找到了空闲位置，存放新接受的套接字信息
            _fd_array[pos] = sock;
            PrinfFd();
        }
    }
    void Recver(int fd, int pos)
    {
        char buffer[1024];
        ssize_t read_size = read(fd, buffer, sizeof(buffer - 1));
        if (read_size > 0)
        {
            buffer[read_size - 1] = '\0';
            std::cout << "ECHO# " << buffer << std::endl;
            sleep(1000);
        }
        else if (read_size == 0)
        {
            LogMessage(DEBUG, "CLIENT QUIT,CLOSE FD IS %d", fd);
            close(fd);
            _fd_array[pos] = default_fd;
        }
        else
        {
            LogMessage(DEBUG, "RECV ERROR,FD IS  %d", fd);
            close(fd);
            _fd_array[pos] = default_fd;
        }
    }
    // 事件分配器 select 监听到有就绪的套接字 交给分配器处理
    void Dispatcher(fd_set &rfds)
    {
        //遍历准备就绪的文件描述符集合
        for (int i = 0; i < __FD_SETSIZE; ++i)
        {
            int fd = _fd_array[i];
            if (fd == default_fd)
                continue;
            //检查是否就绪
            if (FD_ISSET(fd, &rfds))
            {
                //是否为监听套接字
                if (fd == _listen_fd)
                {
                    Accepter();
                }
                else
                {
                    Recver(fd, i);
                }
            }
        }
    }

private:
    Sock _listen_sock; // 套接字
    int _listen_fd;    // 套接字描述符
    uint16_t _port;    // 端口号
    int _fd_array[__FD_SETSIZE];
};